package com.third.device.mg.serialport.help.netty

import com.third.device.mg.serialport.MGSerialPort
import com.third.device.mg.serialport.listener.BootstrapHelperNotifyListener
import com.third.device.mg.serialport.listener.MGNettyConnectListener
import com.third.device.mg.serialport.utils.SLog
import io.netty.channel.nio.NioEventLoopGroup
import org.jetbrains.annotations.NotNull

/**
 * company 广东玛格家居有限公司
 * @author smoker
 * @Date 2021/12/31
 * Description:Netty 框架  Socket Bootstrap 管理者
 */
internal class BootstrapManager :BootstrapHelperNotifyListener{
    /**
     * Netty 客户端 引导类 缓存类
     */
    private val clientMap by lazy { HashMap<String, BootstrapHelper>() }

    /**
     * Netty 客户端 正在连接中...
     */
    private val tempMap by lazy { HashMap<String, BootstrapHelper>() }

    //线程池
    private val loopGroup by lazy { NioEventLoopGroup(4) }

    private var listener: MGNettyConnectListener? = null



    companion object {
        private const val TAG = "${MGSerialPort.BASE_TAG}:BootstrapManager"
        fun createKey(ip: String, port: Int) = "${ip}:$port"
    }


    /**
     * 检查是否已经连接
     */
    fun checkConnect(@NotNull ip:String ,port:Int):Boolean{
        val key = createKey(ip, port)
        clientMap[key]?.let {
            return it.isConnect()
        }?:let {
            return false
        }
    }
    /**
     * 创建Netty客户端
     * 如果已经存在，则不创建，判断是否连接，已经连接，不处理，如果未连接，则重新连接
     * 如果不存在，则进行创建
     */
    fun createClient(ip: String, port: Int) {
        val key = createKey(ip, port)
        if (clientMap.containsKey(key) || tempMap.containsKey(key)){
            //说明已经存在
            clientMap.remove(key)?.let { it->
                tempMap[key] = it
                if (!it.isConnect()) {
                    SLog.d(TAG, "Netty 旧对象连接 $ip:$port")
                    it.connect()
                }else{
                    SLog.d(TAG, "Netty 已经连接 ,忽略当前连接请求 $ip:$port")
                }
            }?:let {
                SLog.d(TAG, "Netty 当前对象正在连接中,忽略当前连接请求 $ip:$port")
            }
        }else{
            //未存在，进行创建
            SLog.d(TAG, "Netty 新对象连接 $ip:$port")
            val boots = BootstrapHelper(ip, port, loopGroup ,this)
            listener?.let {
                boots.setListener(it)
            }
            tempMap[key] = boots
        }

        /*clientMap[key]?.let {
            *//*如果已有Netty数据，但是已断开连接，那么重新连接*//*
            if (!it.isConnect()) {
                SLog.d(TAG, "Netty 旧对象连接 $ip:$port")
                it.connect()
            }
            return it
        } ?: let {
            SLog.d(TAG, "Netty 新对象连接 $ip:$port")
            val boots = BootstrapHelper(ip, port, loopGroup)
            listener?.let {
                boots.setListener(it)
            }
            clientMap[key] = boots
            return boots
        }*/
    }






    fun setListener(listener: MGNettyConnectListener) {
        this.listener = listener
        for ((_, client) in clientMap) {
            client.setListener(listener)
        }
    }


    /**
     * 写入数据
     * @param ip   目标IP地址
     * @param port 目标端口
     * @param content 写入的内容
     */
    fun write(@NotNull ip: String, @NotNull port: Int,  @NotNull content: ByteArray) {
        val key = createKey(ip, port)
        clientMap[key]?.writeData(content)?:let {
            SLog.d(TAG, "未有已经连接的Netty $ip:$port")
            listener?.errorBack(ip ,port , Throwable("未有已经连接的Netty ,请检查是否已连接Netty"))
        }
    }

    /**
     * 关闭指定的socket
     */
    fun onDestroy(@NotNull ip: String, @NotNull port: Int){
        val key = createKey(ip, port)
        clientMap.remove(key)?.disconnect()
    }

    /**
     * 关闭所有Socket
     */
    fun onDestroy() {
        loopGroup.shutdownGracefully()
        clientMap.clear()
        //此处不需要再单独回调，因为每个netty里面有监听通道
        /*listener?.let {
            for ((_, client) in clientMap) {
                it.disconnectBack(client.ip ,client.port)
            }
        }*/

    }

    /**
     * 引导助手通知监听器
     * 用来更新 Netty客户端 是在操作中 ，还是已经静态缓存中
     * 客户端连接 回调后，从tempMap转移到clientMap上
     */
    override fun operationComplete(isConnect: Boolean, ip: String, port: Int) {
        val key = createKey(ip, port)
        tempMap.remove(key)?.let {
            clientMap[key] = it
        }
    }


}